#include "gamecore.h"
#include "gamelua.h"
#include <fstream>
#include <iostream>
#include <cstdlib>
#include "dir.h"
#include "xmlsp_dom.h"
#include "card.h"

using namespace std;

/**
 * load_card:
 * @name: the XMLfile name.
 * load card info from a XMLfile.
 * return value: Card object, or %NULL if load failed.
 **/
Card *GameCore::load_card(const char *filename)
{
	ifstream is;
	string xml;
	char buff[1024];

	//read XMLfile
	try {
		is.open(filename, ifstream::in);
		if (!is) {
			throw "open file failed!";
		}

		while (!is.eof() && is.good()) {
			is.read(buff, sizeof(buff));
			xml.append(buff, is.gcount());
		}
		if (is.bad()) {
			throw "read file failed!";
		}
		is.close();
	}
	catch(const char *str) {
		cerr << filename << ": " << str << endl;
		return NULL;
	}

	//parse XML
	Card *card = NULL;
	XMLSP::DOMElement *root = NULL;
	string cardname;
	MagicColor cardcolor = MAGIC_RED;
	string cardability;
	string carddescribe;
    string imagefile;
    string imagefile_s;
	//int costR=0, costG=0, costB=0;
	int cost=0;

	try {
		//get root
		root = XMLSP::DOMElement::loadXML(xml);
		if (NULL == root) {
			throw "parse XML failed!";
		}
		XMLSP::DOMElements els;
		if (root->getElementName() != "card") {
			throw "XML format wrong!";
		}

		//card name
		cardname = root->getAttribute("name");

		//card cost
		string strcost = root->getAttribute("cost");
		if (strcost.size() <= 0 ) {
			throw "XML format wrong: no attribute 'cost'";
		}
		cost = atoi(strcost.c_str());

		//card color
		string strcolor = root->getAttribute("color");
		if (strcolor == "red") {
			cardcolor = MAGIC_RED;
		} else if (strcolor == "green") {
			cardcolor = MAGIC_GREEN;
		} else if (strcolor == "blue") {
			cardcolor = MAGIC_BLUE;
		} else {
			throw "XML format wrong: 'color' don't have data or have wrong data.";
		}

#if 0
		//cost R G B
		els = root->getElementsByName("cost");
		if (els.size() <= 0) {
			throw "XML format wrong: no 'cost' tag";
		}
		string strcost;
		strcost = els[0]->getAttribute("red");
		if (strcost.size() <= 0 ) {
			throw "XML format wrong: no attribute 'red' in 'cost' tag";
		}
		costR = atoi(strcost.c_str());
		strcost = els[0]->getAttribute("green");
		if (strcost.size() <= 0 ) {
			throw "XML format wrong: no attribute 'green' in 'cost' tag";
		}
		costG = atoi(strcost.c_str());
		strcost = els[0]->getAttribute("blue");
		if (strcost.size() <= 0 ) {
			throw "XML format wrong: no attribute 'blue' in 'cost' tag";
		}
		costB = atoi(strcost.c_str());
#endif

		//card describe
		els = root->getElementsByName("describe");
		if (els.size() <= 0) {
			throw "XML format wrong: no 'describe' tag";
		}
		carddescribe = els[0]->getCData();

		//card ability (Lua code)
        string luafile;
        string luapath;
        ifstream iflua;
		els = root->getElementsByName("ability");
		if (els.size() <= 0) {
			throw "XML format wrong: no 'ability' tag";
		}
        size_t found;
        luapath = filename;
        found = luapath.find_last_of("/\\");
        luafile = luapath.substr(0, found+1);
        luafile.append(els[0]->getCData());
        iflua.open(luafile.c_str(), ifstream::in);
		if (!iflua) {
			throw "open lua file failed! ";
		}
		while (!iflua.eof() && iflua.good()) {
			iflua.read(buff, sizeof(buff));
            cardability.append(buff, iflua.gcount());
		}
		if (iflua.bad()) {
			throw "read lua file failed! ";
		}
		iflua.close();

        //card image path
        els = root->getElementsByName("image");
		if (els.size() <= 0) {
			throw "XML format wrong: no 'image' tag";
		}
		imagefile = els[0]->getCData();

        els = root->getElementsByName("image_s");
		if (els.size() <= 0) {
			throw "XML format wrong: no 'image_s' tag";
		}
		imagefile_s = els[0]->getCData();

		//build Card object
		card = new Card(cardname, cost, cardcolor, carddescribe, cardability, imagefile, imagefile_s);

#if 0
//#ifdef __DEBUG__
		cout << "name:" << cardname << endl;
		cout << "color:" << cardcolor << endl;
		cout << "cost:" << cost << endl;
		cout << "describe:" << carddescribe << endl;
		cout << "ability:" << cardability << endl;
#endif

	}
	catch(const char *str) {
		cerr << filename << ": " << str << endl;
	}
    if (root != NULL) {
        delete root;
    }

	return card;
}

//static const char *DATADIRNAME = "./data";

/**
 * load_all_cards:
 * @path: the directory contain XMLfiles.
 * load all cards from the specified directory.
 **/
void GameCore::load_all_cards(const char *path)
{
	size_t i;
	Card *card = NULL;
	vector<string> filenames = DIROprations::get_all_filename(path, ".xml");
	for (i=0; i<filenames.size(); i++) {
		string filepath = DIROprations::build_fullpath(path, filenames[i]);
		card = load_card(filepath.c_str() );
		if (NULL != card) {
			//cardmap.insert(pair<string, Card *>(card->get_name(), card));
            cardmap.push_back(card);
		}
	}
}

void GameCore::swap_player()
{
    if (cur_playerID == PLAYER_1) {
        cur_playerID = PLAYER_2;
        cur_player = player2;
    } else {
        cur_playerID = PLAYER_1;
        cur_player = player1;
    }
}

bool GameCore::is_card_playable(enum PlayerID p, int index)
{
    bool playable = false;
    Card *card = NULL;
    Player *player = NULL;
    Card **handcard = NULL;

    if (p == PLAYER_1) {
        player = player1;
        handcard = handcard_array1;
    } else if (p == PLAYER_2) {
        player = player2;
        handcard = handcard_array2;
    } else {
        return false;
    }

    if (index >= MAX_HANDCARD_NUM) {
        return false;
    }
    if (handcard[index] == NULL) {
        return false;
    }
    card = handcard[index];
    if (player->get_manapoint(card->get_color()) >= card->get_cost()) {
        playable = true;
    }

    return playable;
}

bool GameCore::play_a_card(enum PlayerID p, int index)
{
    Card *card = NULL;
    Player *player = NULL;
    Card **handcard = NULL;

    if (p == PLAYER_1) {
        player = player1;
        handcard = handcard_array1;
    } else if (p == PLAYER_2) {
        player = player2;
        handcard = handcard_array2;
    } else {
        return false;
    }
    if (index >= MAX_HANDCARD_NUM) {
        return false;
    }
    if (handcard[index] == NULL) {
        return false;
    }
    card = handcard[index];
    enum MagicColor manacolor = card->get_color();
    int manapoint = player->get_manapoint(manacolor);
    if (manapoint >= card->get_cost()) {
        player->set_manapoint(manacolor, manapoint - card->get_color());
        if (gamelua_do(card->get_ability().c_str()) != 0) {
            cerr << "run lua error" << endl;
            return false;
        }
    } else {
        return false;
    }
    clog << "player " << p << " play: " + card->get_name() << endl;
    discard_a_card(p, index);

    return true;
}

bool GameCore::discard_a_card (enum PlayerID p, int index)
{
    Card **handcard = NULL;

    if (p == PLAYER_1) {
        handcard = handcard_array1;
    } else if (p == PLAYER_2) {
        handcard = handcard_array2;
    } else {
        return false;
    }
    if (index >= MAX_HANDCARD_NUM) {
        return false;
    }
    if (handcard[index] == NULL) {
        return false;
    }
    clog << "player " << p << " discard: " + handcard[index]->get_name() << endl;
    handcard[index] = NULL;
    return true;
}

bool GameCore::draw_a_card(enum PlayerID p, int index)
{
    size_t cardid=0;
    Card **handcard = NULL;

    if (cardmap.size() <= 0) {
        return false;
    }
    if (p == PLAYER_1) {
        handcard = handcard_array1;
    } else if (p == PLAYER_2) {
        handcard = handcard_array2;
    } else {
        return false;
    }
    if (index >= MAX_HANDCARD_NUM) {
        return false;
    }
    if (handcard[index] != NULL) {
        return false;
    }
    cardid = (int) ((float)cardmap.size()*rand()/(RAND_MAX+1.0));
    handcard[index] = cardmap[cardid];
    clog << "player " << p << " draw: " + handcard[index]->get_name() << endl;

    return true;
}

Card * GameCore::get_card (enum PlayerID p, int index)
{
    Card **handcard = NULL;

    if (p == PLAYER_1) {
        handcard = handcard_array1;
    } else if (p == PLAYER_2) {
        handcard = handcard_array2;
    } else {
        return NULL;
    }
    if (index >= MAX_HANDCARD_NUM) {
        return NULL;
    }
    return handcard[index];
}

size_t GameCore::get_handcard_number(enum PlayerID p)
{
    Card **handcard = NULL;
    size_t count = 0;

    if (p == PLAYER_1) {
        handcard = handcard_array1;
    } else if (p == PLAYER_2) {
        handcard = handcard_array2;
    } else {
        return 0;
    }

    int i;
    for (i=0; i<MAX_HANDCARD_NUM; i++) {
        if (handcard[i] != NULL) {
            count++;
        }
    }
    return count;
}

GameCore::GameCore() :
    cur_playerID(PLAYER_1)
{
    srand(0);
    player1 = new Player();
    player2 = new Player();
    cur_player = player1;
    memset(handcard_array1, 0, sizeof(handcard_array1));
    memset(handcard_array2, 0, sizeof(handcard_array2));
}

GameCore::~GameCore()
{
	/*map<string, Card *>::iterator p;
	p = cardmap.begin();
	while (p != cardmap.end()) {
		delete p->second;
		p++;
	}*/
    size_t i;
    for (i=0; i<cardmap.size(); i++) {
        delete cardmap[i];
    }
	cardmap.clear();

    if (player1) {
        delete player1;
    }
    if (player2) {
        delete player2;
    }
}

/**
 * print all cards whitch in the cardmap
 * for debug
 */
void GameCore::print_all_cards ()
{
    /*
	map<string, Card *>::iterator p;
    vector<Card *>::iterator p;
	p = cardmap.begin();
	while (p != cardmap.end()) {
		p->second->print_card();
		p++;
	}*/
    size_t i;
    for (i=0; i<cardmap.size(); i++) {
        cardmap[i]->print_card();
    }
}

